﻿using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml.Linq;

namespace MockingBird.Simulator.Framework.Configuration
{
    using MockingBird.Common.Infrastructure.Configuration;

    /// <summary>
    /// Manages everything to do with the handler mapping (registrations and endpoint/handler mappings)
    /// In MB v2, this just helps write more entries (for the programmatic config creation)
    /// in future versions it will be expanded and access to all handler map info will be exclusively controlled here.
    /// </summary>
    public class HandlerMapManager
    {
        private string handlerInfoFile;
        private const string HandlerRegistrationSectionName = "HandlerRegistration";
        private const string HandlerMapSectionName = "HandlerMap";
        private HandlerMapInfo handlerMapInfo;
        private HandlerRegistrationInfo handlerRegInfo;


        public HandlerMapManager(string configFile)
        {

            this.handlerInfoFile = configFile;
            this.handlerMapInfo = new HandlerMapInfo();
            this.handlerRegInfo = new HandlerRegistrationInfo();
            this.LoadMapInfo();
            this.LoadRegInfo();
        }

        public HandlerMapInfo HandlerMap
        {
            get
            {
                this.LoadMapInfo();
                return this.handlerMapInfo;
            }
        }

        public HandlerRegistrationInfo HandlerRegistrations
        {
            get
            {
                this.LoadRegInfo();
                return this.handlerRegInfo;
            }
        }



        public void AddHandlerMapEntry(HandlerMapEntry entry)
        {
            if (this.handlerMapInfo.GetEntries().Count == 0)
            {
                this.LoadMapInfo();
            }

            this.handlerMapInfo.AddEntry(entry);

        }

        public void AddHandlerRegistrationEntry(HandlerRegistrationEntry entry)
        {
            if (this.handlerRegInfo.GetEntries().Count == 0)
            {
                this.LoadRegInfo();
            }

            this.handlerRegInfo.AddEntry(entry);

        }

        public List<string> GetRegisteredEndpoints()
        {
            List<string> endpoints = new List<string>();
            if (this.handlerMapInfo.GetEntries().Count == 0)
            {
                this.LoadMapInfo();
            }
            if (this.handlerRegInfo.GetEntries().Count == 0)
            {
                this.LoadRegInfo();
            }
            foreach (HandlerMapEntry entry in this.handlerMapInfo.GetEntries())
            {
                endpoints.Add(entry.Endpoint);
            }

            return endpoints;
        }


        private void LoadMapInfo()
        {
            string mapInfoXml = ConfigurationUtils.GetConfigSectionXml(handlerInfoFile, HandlerMapSectionName);
            this.handlerMapInfo.LoadInfoFromXml(mapInfoXml);
        }

        private void LoadRegInfo()
        {
            string handlerInfoXml = ConfigurationUtils.GetConfigSectionXml(handlerInfoFile, HandlerRegistrationSectionName);
            this.handlerRegInfo.LoadInfoFromXml(handlerInfoXml);

        }

        public void SaveConfiguration()
        {
            StreamWriter sw = new StreamWriter(this.handlerInfoFile, false, Encoding.UTF8);
            this.SaveConfiguration(sw);
        }

        public void SaveConfiguration(StreamWriter targetStreamWriter)
        {
            XElement configurationElement = this.CreateConfiguration();
            using (targetStreamWriter)
            {
                targetStreamWriter.Write(configurationElement.ToString(SaveOptions.None));
            }

        }

        private XElement CreateConfiguration()
        {
            // recreate the configuration structure by creating a configuration level XElement
            // and then adding in the XElement corresponding to the internals
            XElement configurationElement = new XElement("configuration");
            configurationElement.Add(this.handlerMapInfo.SerializeToXElement());
            configurationElement.Add(this.handlerRegInfo.SerializeToXElement());
            return configurationElement;

        }



    }
}
